package com.tocean.app.config;

import cn.hutool.core.date.DateUtil;
import io.swagger.annotations.Api;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.http.HttpMethod;
import org.springframework.util.StopWatch;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import springfox.documentation.builders.*;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.schema.ScalarType;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Profile({"dev", "test"})
@EnableOpenApi
@Configuration("frameworkSwagger3Config")
public class SwaggerConfig implements WebMvcConfigurer {

    @Value("${server.servlet.context-path}")
    private String serverServletContextPath;

    @Value("${server.port}")
    private String serverPort;

    @Bean
    public Docket frameworkAPI() {
        return createDocket("backgroundApi", String.format("(%s/framework/.*)", serverServletContextPath));
    }
    @Bean
    public Docket appFrontAPI() {
        return createDocket("wechatApi", String.format("(%s/app/.*)", serverServletContextPath));
    }


    private Docket createDocket(String groupName, String pathRegex) {
        StopWatch watch = new StopWatch();
        watch.start();

        Docket docket = new Docket(DocumentationType.SWAGGER_2)
//                .pathMapping("/")
                .groupName(groupName) // 定义组
                .apiInfo(apiInfo()) // 配置说明
                .ignoredParameterTypes(HttpServletRequest.class) // 方法参数忽略，例如HttpServletRequest不想展示在Swagger上
                .select() // 选中哪些路径和api会生成Document
                .apis(RequestHandlerSelectors.withClassAnnotation(Api.class)) // 拦截的包路径
                .paths(PathSelectors.regex(pathRegex)) // 拦截的接口路径
                .build() // 创建
//                .produces(new LinkedHashSet<>(Arrays.asList("http", "https")))
                .securitySchemes(securitySchemes())
                .securityContexts(securityContexts())
//                .globalRequestParameters(getGlobalRequestParameters())
                .globalResponses(HttpMethod.GET, getGlobalResponseMessage())
                .globalResponses(HttpMethod.POST, getGlobalResponseMessage())
                .enable(Boolean.TRUE);

        watch.stop();
        log.info("Started Swagger [{}] in [{}] ms, url [http://localhost:{}{}/swagger-ui/index.html?urls.primaryName={}]", groupName, watch.getTotalTimeMillis(), serverPort, serverServletContextPath, groupName);

        return docket;
    }

    private List<SecurityScheme> securitySchemes() {
        ApiKey apiKey = new ApiKey("token", "token", In.HEADER.toString());
        return Collections.singletonList(apiKey);
    }

    private List<SecurityContext> securityContexts() {
        return Collections.singletonList(
                SecurityContext.builder()
                        .securityReferences(Collections.singletonList(new SecurityReference("token", new AuthorizationScope[]{new AuthorizationScope("global", "")})))
                        .build()
        );
    }

    /**
     * 功能描述：生成全局通用的参数
     *
     * @return
     */
    private List<RequestParameter> getGlobalRequestParameters() {
        List<RequestParameter> parameterList = new ArrayList();
        parameterList.add(new RequestParameterBuilder()
                .name("authorization")
                .description("authorization")
                .required(Boolean.TRUE)
                .in(ParameterType.HEADER)
                .query(q -> q.model(m -> m.scalarModel(ScalarType.STRING)))
                .build());

        return parameterList;
    }

    /**
     * 生成通用响应信息
     *
     * @return
     */
    private List<Response> getGlobalResponseMessage() {
        List<Response> responseList = new ArrayList();
        responseList.add(new ResponseBuilder().code("404").description("找不到资源").build());
        return responseList;
    }

    private ApiInfo apiInfo() {
        final List<String> descriptionList = new ArrayList<String>();
        descriptionList.add("启动时间: " + DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));

        return new ApiInfoBuilder()
                .title("框架")
                .description(descriptionList.stream().collect(Collectors.joining("<br/>")))
                .contact(new Contact("", "", ""))
                .version("0.0.1")
                .build();
    }

}
